package com.geniusk.app.controller;

import cn.hutool.json.JSONUtil;
import com.geniusk.app.utils.FollowUserUtil;
import com.geniusk.common.constant.CommonConstants;
import com.geniusk.common.core.JSONResult;
import com.geniusk.common.enums.ResponseType;
import com.geniusk.common.utils.PageUtil;
import com.geniusk.common.utils.RedisUtil;
import com.geniusk.file.utils.MinioUtil;
import com.geniusk.security.annotation.PreFuncAuth;
import com.geniusk.security.utils.SecurityUtil;
import com.geniusk.system.model.bo.collectDevice.CollectDeviceByIdBO;
import com.geniusk.system.model.bo.device.AppUpdateDeviceBO;
import com.geniusk.system.model.bo.device.SelectDeviceByIdBO;
import com.geniusk.system.model.bo.device.SelectDeviceByPageBO;
import com.geniusk.system.model.pojo.Device;
import com.geniusk.system.model.pojo.User;
import com.geniusk.system.model.ro.CollectDeviceRO;
import com.geniusk.system.model.vo.PublicDeviceVO;
import com.geniusk.system.model.vo.PublicUserVO;
import com.geniusk.system.service.DeviceService;
import com.geniusk.system.service.ModelService;
import com.geniusk.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.util.*;

import static com.geniusk.common.constant.RedisConstants.COLLECT_DEVICE_USER_KEY;

/**
 * APP设备接口
 */
@RestController
@RequestMapping("/app/device")
public class AppDeviceController {

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private FollowUserUtil followUserUtil;

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private ModelService modelService;

    /**
     * 分页查询设备
     */
    @PostMapping("/selectMyDeviceByPage")
    public JSONResult selectMyDeviceByPage(@Valid @RequestBody SelectDeviceByPageBO selectDeviceByPageBO) {
        Device device = JSONUtil.parse(selectDeviceByPageBO).toBean(Device.class);
        device.setCreateBy(SecurityUtil.getUsername());
        int pageNum = selectDeviceByPageBO.getPageNum();
        int pageSize = selectDeviceByPageBO.getPageSize();
        PageUtil.startPage(pageNum, pageSize);
        List<Device> deviceList = deviceService.selectDeviceByPage(device);
        Map<String, Object> result = PageUtil.getResultTableData(deviceList);
        return JSONResult.ok(result);
    }

    /**
     * 根据ID查询设备
     */
    @PostMapping("/selectMyDeviceById")
    public JSONResult selectMyDeviceById(@Valid @RequestBody SelectDeviceByIdBO selectDeviceByIdBO) {
        Long deviceId = selectDeviceByIdBO.getDeviceId();
        Device device = deviceService.selectDeviceById(deviceId);
        Map<String, Object> result = new HashMap<>();
        result.put("device", device);
        result.put("model",modelService.selectModelVOByModelId(device.getModelId()));
        return JSONResult.ok(result);
    }

    /**
     * 设备封面上传
     */
    @PostMapping("/uploadDeviceCover")
    public JSONResult uploadDeviceCover(@RequestParam("file") MultipartFile file) {
        String contentType = file.getContentType();
        long fileSize = file.getSize();
        if(fileSize / 1024 / 1024 > 10){
            return JSONResult.errorMsg("上传设备封面图片大小不能超过10MB");
        }
        assert contentType != null;
        if(!contentType.equals("image/jpeg") && !contentType.equals("image/png")){
            return JSONResult.errorMsg("上传设备封面图片只能是图片格式");
        }
        try {
            String coverUrl = minioUtil.uploadFile(file);
            Map<String,Object> result = new HashMap<>();
            result.put("coverUrl", coverUrl);
            return JSONResult.ok(result);
        } catch (Exception e) {
            return JSONResult.errorMsg(e.getMessage());
        }
    }

    /**
     * 修改设备
     */
    @PostMapping("/updateDevice")
    public JSONResult updateDevice(@Valid @RequestBody AppUpdateDeviceBO appUpdateDeviceBO) {
        Device device = JSONUtil.parse(appUpdateDeviceBO).toBean(Device.class);
        device.setUpdateBy(SecurityUtil.getUsername());
        int rows = deviceService.updateDevice(device);
        Map<String,Object> result = new HashMap<>();
        result.put("rows",rows);
        return JSONResult.ok(result);
    }

    /**
     * 获取设备令牌
     */
    @PostMapping("/getAccessToken")
    @PreFuncAuth("SYS:DEVICE:TOKEN")
    public JSONResult getAccessToken(@Valid @RequestBody SelectDeviceByIdBO selectDeviceByIdBO) {
        String accessToken = deviceService.getAccessToken(selectDeviceByIdBO.getDeviceId());
        Device device = deviceService.selectDeviceById(selectDeviceByIdBO.getDeviceId());
        Map<String,Object> result = new HashMap<>();
        result.put("url",device.getVideoUrl());
        result.put("accessToken",accessToken);
        return JSONResult.ok(result);
    }

    /**
     * 分页查询公开设备
     */
    @PostMapping("/selectPublicDeviceByPage")
    public JSONResult selectPublicDeviceByPage(@Valid @RequestBody SelectDeviceByPageBO selectDeviceByPageBO) {
        int pageNum = selectDeviceByPageBO.getPageNum();
        int pageSize = selectDeviceByPageBO.getPageSize();
        PageUtil.startPage(pageNum,pageSize);
        List<Device> deviceList = deviceService.selectPublicDeviceByPage();
        Map<String,Object> result = PageUtil.getResultTableData(deviceList);
        return JSONResult.ok(result);
    }

    /**
     * 根据ID查询公开设备
     */
    @PostMapping("/selectPublicDeviceById")
    public JSONResult selectPublicDeviceById(@Valid @RequestBody SelectDeviceByIdBO selectDeviceByIdBO) {
        Long deviceId = selectDeviceByIdBO.getDeviceId();
        Device device = deviceService.selectDeviceById(deviceId);
        if(device.getIsPublic().equals(CommonConstants.NO)){
            return JSONResult.errorCustom(ResponseType.FAILED);
        }
        PublicDeviceVO publicDeviceVO = JSONUtil.parse(device).toBean(PublicDeviceVO.class);
        String collectDeviceUserKey = getCollectDeviceUserKey();
        CollectDeviceRO collectDeviceRO = redisUtil.getCacheObject(collectDeviceUserKey);
        if(collectDeviceRO != null){
            Map<Long, Date> deviceIdMap = collectDeviceRO.getDeviceIdMap();
            boolean collect = deviceIdMap.containsKey(publicDeviceVO.getDeviceId());
            publicDeviceVO.setCollect(collect);
            if(collect){
                publicDeviceVO.setCollectTime(deviceIdMap.get(publicDeviceVO.getDeviceId()));
            }
        }else {
            publicDeviceVO.setCollect(false);
        }
        User user = userService.selectUserByUserName(device.getCreateBy());
        PublicUserVO publicUserVO = JSONUtil.parse(user).toBean(PublicUserVO.class);
        followUserUtil.setFollow(publicUserVO);
        publicDeviceVO.setUser(publicUserVO);
        Map<String, Object> result = new HashMap<>();
        result.put("device", publicDeviceVO);
        result.put("model",modelService.selectModelVOByModelId(device.getModelId()));
        return JSONResult.ok(result);
    }

    /**
     * 收藏设备
     */
    @PostMapping("/collectDeviceById")
    public JSONResult collectDeviceById(@Valid @RequestBody CollectDeviceByIdBO collectDeviceByIdBO) {
        Long deviceId = collectDeviceByIdBO.getDeviceId();
        boolean collect = collectDeviceByIdBO.isCollect();
        Device device = deviceService.selectDeviceById(deviceId);
        if(device == null){
            return JSONResult.errorMsg("收藏的设备不存在");
        }
        String collectDeviceUserKey = getCollectDeviceUserKey();
        setCollectDevice(collectDeviceUserKey, collect, deviceId);
        return JSONResult.ok();
    }

    /**
     * 查询收藏设备数量
     */
    @GetMapping("/selectCollectDeviceCount")
    public JSONResult selectCollectDeviceCount() {
        String collectDeviceUserKey = getCollectDeviceUserKey();
        CollectDeviceRO collectDeviceRO = redisUtil.getCacheObject(collectDeviceUserKey);
        int count = 0;
        if(collectDeviceRO != null){
            Map<Long, Date> deviceIdMap = collectDeviceRO.getDeviceIdMap();
            count = deviceIdMap.size();
        }
        Map<String,Object> result = new HashMap<>();
        result.put("count",count);
        return JSONResult.ok(result);
    }

    /**
     * 分页查询查询收藏设备
     */
    @PostMapping("/selectCollectDeviceByPage")
    public JSONResult selectCollectDeviceByPage() {
        String collectDeviceUserKey = getCollectDeviceUserKey();
        CollectDeviceRO collectDeviceRO = redisUtil.getCacheObject(collectDeviceUserKey);
        List<PublicDeviceVO> deviceInfoVOList = new ArrayList<>();
        if(collectDeviceRO != null){
            Map<Long, Date> deviceIdMap = collectDeviceRO.getDeviceIdMap();
            for (Long deviceId: deviceIdMap.keySet()){
                Device device = deviceService.selectDeviceById(deviceId);
                PublicDeviceVO publicDeviceVO;
                if(device != null){
                    if(device.getIsPublic().equals("1")){
                        publicDeviceVO = JSONUtil.parse(device).toBean(PublicDeviceVO.class);
                        publicDeviceVO.setCollect(true);
                        publicDeviceVO.setCollectTime(deviceIdMap.get(deviceId));
                        User user = userService.selectUserByUserName(device.getCreateBy());
                        PublicUserVO publicUserVO = JSONUtil.parse(user).toBean(PublicUserVO.class);
                        followUserUtil.setFollow(publicUserVO);
                        publicDeviceVO.setUser(publicUserVO);
                    }else{
                        publicDeviceVO = new PublicDeviceVO();
                        publicDeviceVO.setDeviceId(deviceId);
                        publicDeviceVO.setDeviceName("设备已失效");
                        publicDeviceVO.setRemark("设备未公开或已删除");
                        publicDeviceVO.setType("-1");
                    }
                }else{
                    publicDeviceVO = new PublicDeviceVO();
                    publicDeviceVO.setDeviceId(deviceId);
                    publicDeviceVO.setDeviceName("设备已失效");
                    publicDeviceVO.setRemark("设备未公开或已删除");
                    publicDeviceVO.setType("-1");
                }
                deviceInfoVOList.add(publicDeviceVO);

            }
        }
        Map<String,Object> result = new HashMap<>();
        result.put("list",deviceInfoVOList);
        return JSONResult.ok(result);
    }

    private void setCollectDevice(String collectDeviceUserKey, boolean collect, Long deviceId){
        Boolean hasCollectDeviceUserKey = redisUtil.hasKey(collectDeviceUserKey);
        CollectDeviceRO collectDeviceRO;
        if(hasCollectDeviceUserKey){
            collectDeviceRO = redisUtil.getCacheObject(collectDeviceUserKey);
        }else{
            collectDeviceRO = new CollectDeviceRO();
            Map<Long, Date> deviceIdMap = new HashMap<>();
            collectDeviceRO.setDeviceIdMap(deviceIdMap);
        }
        Map<Long, Date> deviceIdMap = collectDeviceRO.getDeviceIdMap();
        if(collect){
            if(!deviceIdMap.containsKey(deviceId)){
                deviceIdMap.put(deviceId,new Date());
                redisUtil.setCacheObject(collectDeviceUserKey,collectDeviceRO);
            }
        }else{
            deviceIdMap.remove(deviceId);
            if(deviceIdMap.isEmpty()){
                redisUtil.deleteObject(collectDeviceUserKey);
            }else{
                redisUtil.setCacheObject(collectDeviceUserKey,collectDeviceRO);
            }
        }
    }

    /**
     * 获取用户关注缓存Key
     * @return 关注粉丝缓存Key
     */
    private String getCollectDeviceUserKey(){
        return COLLECT_DEVICE_USER_KEY + SecurityUtil.getUserId();
    }
}
